from cmath import *

class Similarity:
    """
    A transformation of the form z -> Az + B or z ->Az_ + B.
    """
    def __init__(self, a, b, flip=0):
        self.A = a
        self.B = b
        self.flip = flip

    def __repr__(self):
        if self.flip:
            return "z -> %sz_ + %s"%(`self.A`, `self.B`)
        return "z -> %sz + %s"%(`self.A`, `self.B`)

    def __mul__(self, other):
        flip = self.flip^other.flip
        if self.flip:
          return Similarity(self.A*other.A.conjugate(),
                            self.A*other.B.conjugate() + self.B, flip) 
        else:
          return Similarity(self.A*other.A , self.A*other.B + self.B, flip) 

    def __call__(self, z):
        return self.A*z + self.B

def ChainSims(left, right):
    """
    [x1,...xn], [y1,...,ym] -> [x1y1,x1y2,...,x1yk,...,xny1,...xnyk].
    """
    result = []
    for sim in left:
        result += map( sim.__mul__, right )
    return result

def PolygonToSimlist(polygon):
    """
    Returns a list of similarities that map [0,1] to the sides of a polygon.
    """
    result = []
    
    z0 = polygon[0]
    for z in polygon[1:]:
        z1 = z
        result.append( Similarity(z1-z0, z0) )
        z0=z1
    return result

def zToPixels(window_width, window_height, z_center, z_width, z):
    """
    Computes the screen coordinates of a complex number.
    """
    z = complex(z)
    pixel_size = float(z_width)/window_width
    left = z_center.real - window_width*pixel_size/2
    top = z_center.imag + window_height*pixel_size/2
    return (int((z.real - left)/pixel_size), int((top - z.imag)/pixel_size)) 

def SimlistToPixels(simlist, W, H, z_center=0+.4j, z_width=2):
    """
    Returns a list of screen coordinates of the images of 0 and 1.
    """
    points = []
    for sim in simlist:
        points += zToPixels(W, H, z_center, z_width, sim(0))
        points += zToPixels(W, H, z_center, z_width, sim(1))
    return points
    
